import { AbstractRenderer } from "./AbstractRenderer";
import { Transform } from "./Transform";
import { RectangleShapeRenderer } from "./RectangleShapeRenderer";
import { TextRenderer } from "./TextRenderer";
import { BitmapRenderer } from "./BitmapRenderer";
import { Behaviour } from "./Behaviour";
import { GameObject } from "./GameObject";
import { System } from "./System";
import { Camera } from "./Camera";
import { invertMatrix, matrixAppendMatrix } from "../math";


export class RenderingSystem extends System {

    list: AbstractRenderer[] = [];
    camera: Camera;

    onAddBehaviour(gameObject: GameObject, behaviour: Behaviour) {
        if (behaviour instanceof BitmapRenderer ||
            behaviour instanceof TextRenderer ||
            behaviour instanceof RectangleShapeRenderer) {
            gameObject.renderer = behaviour;
            this.list.push(behaviour);
        }

        if (behaviour instanceof Camera) {
            this.camera = behaviour;
        }
    }

    onFrame() {
        const canvas = document.getElementById('gameCanvas') as HTMLCanvasElement;
        const context = canvas.getContext('2d');
        context.save();
        context.clearRect(0, 0, canvas.width, canvas.height);
        this.draw(this.rootGameObject);
        context.restore();
    }

    private draw(gameObject: GameObject) {
        const canvas = document.getElementById('gameCanvas') as HTMLCanvasElement;
        const context = canvas.getContext('2d');
        const transform = gameObject.getBehaviour(Transform);
        const modelMatrix = transform.globalMatrix;

        let globalMatrix = modelMatrix;
        if (this.camera) {
            const cameraTransform = this.camera.gameObject.getBehaviour(Transform)
            const viewportMatrix = invertMatrix(cameraTransform.globalMatrix);
            globalMatrix = matrixAppendMatrix(modelMatrix, viewportMatrix);
        }

        context.globalAlpha = transform.globalAlpha;
        context.setTransform(globalMatrix.a, globalMatrix.b, globalMatrix.c, globalMatrix.d, globalMatrix.tx, globalMatrix.ty);
        const renderer = gameObject.renderer;
        if (renderer) {
            renderer.render(context);
        }
        for (const childGameObject of gameObject.children) {
            this.draw(childGameObject);
        }

    }
}
